import weakref
from game.room import Room

class GameRoom(Room):
    # roles = (
    # ('role_a', 3),('role_b', 4)
    # )
    roles = ()

    def __init__(self):
        Room.__init__(self)
        self.__roles = {}
        self.__info = {}
        self.__playing = False

        for role, _ in self.roles:
            self.__roles[role] = weakref.WeakKeyDictionary()

    def __find_unassigned_role(self):
        for role, num in self.roles:
            if len(self.__roles[role]) < num:
                return role
        else:
            return None

    def on_player_leave(self, player):
        Room.on_player_leave(self, player)
        if self.get_player_state(player):
            self.role_unassign(player)
            self.on_game_interrupt()
            self.game_end()

    def on_player_enter(self, player):
        Room.on_player_enter(self, player)
        self.role_auto_assign(player)
        self.role_state_broadcast()

    def role_auto_assign(self, player):
        self.role_unassign(player)
        role = self.__find_unassigned_role()
        if role is not None:
            self.__role_assign_uncheck(player, role)

    def role_unassign(self, player):
        role = self.__info.pop(player.id, None)
        if role is not None:
            self.__roles[role].pop(player)

    def role_assign(self, player, role):
        for r, num in self.roles:
            if r == role:
                if len(self.__roles[role]) < num:
                    self.role_unassign(player)
                    self.__role_assign_uncheck(player, role)
                    return True
                return False
        return False

    def role_exchange(self, p1, p2):
        if p1.id in self.__info and p2.id in self.__info:
            r1 = self.__info[p1.id]
            r2 = self.__info[p2.id]
            self.role_unassign(p1)
            self.role_unassign(p2)
            self.__role_assign_uncheck(p1, r2)
            self.__role_assign_uncheck(p2, r1)
            return True
        return False

    def __role_assign_uncheck(self, player, role):
        self.__info[player.id] = role
        self.__roles[role][player] = 'preparing'

    def role_get_all_info(self):
        ret = []
        for role, _ in self.roles:
            for p, state in self.__roles[role].iteritems():
                ret.append({'id':p.id, 'name':p.name, 'role':role, 'state':state})
        return ret

    def role_get_players(self, role):
        return self.__roles.get(role, {}).keys()

    def get_player_role(self, player):
        return self.__info.get(player.id, None)

    def get_player_state(self, player):
        role = self.__info.get(player.id, None)
        if role is not None:
            return self.__roles[role][player]
        return None

    def role_state_broadcast(self):
        self.broadcast('role_update', {
                        'players': self.role_get_all_info()
                         })

    def _handle_role_assign(self, player, message):
        role = message['role']
        if self.role_assign(player, role):
            self.role_state_broadcast()

    def _handle_role_get_states(self, player, message):
        self.role_state_broadcast();

    def _handle_state_ready(self, player, message):
        if self.__playing:
            raise Exception('game is started')
        role = self.__info[player.id]
        self.__roles[role][player] = 'ready'
        if self.__is_all_ready():
            self.__set_all_state('playing')
            self.__playing = True
            self.on_game_start()

        self.role_state_broadcast()

    def _handle_state_unready(self, player, message):
        if self.__playing:
            raise Exception('game is started')
        role = self.__info[player.id]
        self.__roles[role][player] = 'preparing'
        self.role_state_broadcast()

    def __is_all_ready(self):
        for role, num in self.roles:
            if len(self.__roles[role]) < num:
                return False
            for st in self.__roles[role].itervalues():
                if st != 'ready':
                    return False
        return True

    def game_end(self):
        self.__set_all_state('preparing')
        self.__playing = False
        self.role_state_broadcast()

    def __set_all_state(self, state):
        for role, _ in self.roles:
            for player in self.__roles[role]:
                self.__roles[role][player] = state

    def is_playing(self):
        return self.__playing

    def on_game_start(self):
        pass

    def on_game_interrupt(self):
        pass

